﻿/*
 * Autore: Artur Tolstenco
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Input;
using RecipesManager.Data;
using RecipesManager.MainControls.GenericUserControls;
using RecipesManager.MainControls.RecipeSubControls;
using Application = System.Windows.Application;
using Button = System.Windows.Controls.Button;
using ButtonBase = System.Windows.Controls.Primitives.ButtonBase;
using Cursors = System.Windows.Input.Cursors;
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
using MessageBox = System.Windows.MessageBox;
using RecipesManager.RecipesImporter;


namespace RecipesManager.MainControls
{
    /// <summary>
    /// Interaction logic for RecipeUserControl.xaml
    /// </summary>
    public partial class RecipeUserControl : IMyUserControls, ISwitchable
    {
        readonly RecipeMainPane _panel;
        readonly IngredientSubControl _addIngredientControl;
        readonly StepSubControl _addStepControl;
        readonly NoteSubControl _addNoteControl;
        bool _refreshing;


        public string SectionName { get { return (string)Application.Current.FindResource("RecipesSectionLabel"); } }

        public RecipeUserControl()
        {
            InitializeComponent();

            Refresh_Recipe_List();

            _panel = new RecipeMainPane();
            _panel.bt_add_ingredient.Click += Bt_Add_Edit_Ingredient_Click;
            _panel.bt_edit_ingredient.Click += Bt_Add_Edit_Ingredient_Click;
            _panel.bt_aggiungi_passo_prima.Click += Bt_Add_Edit_Step_Click;
            _panel.bt_aggiungi_passo_dopo.Click += Bt_Add_Edit_Step_Click;
            _panel.bt_modifica_passo.Click += Bt_Add_Edit_Step_Click;
            _panel.bt_add_try.Click += Bt_Add_Try_Click;


            _addIngredientControl = new IngredientSubControl();
            _addIngredientControl.bt_chiudi.Click += Bt_Chiudi_Ingredient_Control_Click;
            _addIngredientControl.bt_salva.Click += Bt_Salva_Ingredient_Control_Click;

            _addStepControl = new StepSubControl();
            _addStepControl.bt_chiudi.Click += Bt_Chiudi_Step_Control_Click;
            _addStepControl.bt_salva.Click += Bt_Salva_Step_Control_Click;


            _addNoteControl = new NoteSubControl();
            _addNoteControl.bt_salva.Click += Bt_Salva_Note_Control_Click;
            _addNoteControl.bt_chiudi.Click += Bt_Chiudi_Note_Control_Click;


            CommandManager.RegisterClassCommandBinding(typeof(RecipeUserControl), _savebinding);
            CommandManager.RegisterClassCommandBinding(typeof(RecipeUserControl), _closebinding);
        }

        void Refresh_Recipe_List()
        {
            Mouse.OverrideCursor = Cursors.Wait;
            _refreshing = true;
            var selectedItem = lb_items.SelectedItem;
            lb_items.Items.Clear();
            foreach (var recipe in Manager.Recipes.Where(i => i.Name.ToLower().Contains(tb_search.Text.ToLower())))
                lb_items.Items.Add(recipe.Name);
            lb_items.SelectedItem = selectedItem;
            _refreshing = false;
            Mouse.OverrideCursor = null;
        }

        public bool Save_Context()
        {
            if (_panel.Editing)
            {
                if (_panel.IsModified())
                {
                    //"Vuoi salvare le modifiche?"
                    var result = MessageBox.Show((string) Application.Current.FindResource("want_to_save"),
                                                 (string) Application.Current.FindResource("notification_dialog_type"),
                                                 MessageBoxButton.YesNoCancel,
                                                 MessageBoxImage.Warning);

                    switch (result)
                    {
                        case MessageBoxResult.Yes:
                            Mouse.OverrideCursor = Cursors.Wait;
                            var r = _panel.SaveCurrentRecipe();
                            Mouse.OverrideCursor = Cursors.Wait;
                            return r;
                        case MessageBoxResult.No:
                            break;
                        case MessageBoxResult.Cancel:
                            return false;
                    }
                }
                return true;
            }
            return true;
        }


        #region events_handler_RecipeMainPane

        void Bt_Add_Edit_Ingredient_Click(object sender, RoutedEventArgs e)
        {
            var b = sender as Button;
            if (b == null)
                return;

            Mouse.OverrideCursor = Cursors.Wait;
            _addIngredientControl.ExistingIngredients = _panel.lv_ingredients.Items.Cast<IngredientFromRecipe>().Select(i => i.Name);
            _addIngredientControl.CurrentRecipeName = _panel.CurrentRecipe;
            _addIngredientControl.CurrentMeasureFamily = _panel.CurrentMeasureFamily;

            if (b.Equals(_panel.bt_add_ingredient))
                _addIngredientControl.CurrentIngredient = null;
            else
                _addIngredientControl.CurrentIngredient = _panel.lv_ingredients.SelectedItem as IngredientFromRecipe;
            
            rightContentPane.Content = _addIngredientControl;

            Mouse.OverrideCursor = null;
        }

        void Bt_Add_Edit_Step_Click(object sender, RoutedEventArgs e)
        {
            var b = sender as Button;
            if (b == null)
                return;

            Mouse.OverrideCursor = Cursors.Wait;
            _addStepControl.CurrentRecipeName = _panel.CurrentRecipe;
            _addStepControl.SelectedId = -1;
            if (_panel.lv_steps.SelectedItems.Count > 0)
                _addStepControl.SelectedId = _panel.steps.IndexOf(_panel.lv_steps.SelectedItems[_panel.lv_steps.SelectedItems.Count - 1] as StepFromRecipe);
            
            if (b.Equals(_panel.bt_aggiungi_passo_prima))
            {
                _addStepControl.AddBefore = true;
                _addStepControl.CurrentStep = null;
            }
            else if (b.Equals(_panel.bt_aggiungi_passo_dopo))
            {
                _addStepControl.AddBefore = false;
                _addStepControl.CurrentStep = null;
            }
            else if (b.Equals(_panel.bt_modifica_passo))
            {
                _addStepControl.CurrentStep = _panel.lv_steps.SelectedItem as StepFromRecipe;
            }

            rightContentPane.Content = _addStepControl;
            Mouse.OverrideCursor = null;
        }

        void Bt_Add_Try_Click(object sender, RoutedEventArgs e)
        {
            var b = sender as Button;
            if (b == null)
                return;

            Mouse.OverrideCursor = Cursors.Wait;
            _addNoteControl.CurrentRecipeName = _panel.CurrentRecipe;
            rightContentPane.Content = _addNoteControl;
            Mouse.OverrideCursor = null;
        }

        #endregion

        #region event_handlers_for_IngredientSubControl

        void Bt_Salva_Ingredient_Control_Click(object sender, RoutedEventArgs routedEventArgs)
        {
            if (_addIngredientControl.IsModified())
            {
                //controllo se tutto è valido...
                var selectedIngredient = _addIngredientControl.cb_ingredients.SelectedItem as string;
                if (selectedIngredient == null)
                {
                    ShowNotificationDialog("Si assicuri di aver selezionato un'ingrediente.");
                    _addIngredientControl.cb_ingredients.Focus();
                    return;
                }

                var currentQuantity = _addIngredientControl.tb_quantity.Text;
                double currentQuantityNumber;

                if (currentQuantity.Equals(""))
                {
                    ShowNotificationDialog("Si assicuri di aver inserito una quantità.");
                    _addIngredientControl.tb_quantity.Focus();
                    return;
                }
                try
                {
                    Double.TryParse(currentQuantity, out currentQuantityNumber);
                }
                catch (ArgumentException)
                {
                    ShowNotificationDialog("Si assicuri di aver inserito un numero come quantità.");
                    _addIngredientControl.tb_quantity.Focus();
                    return;
                }
                if (Math.Abs(currentQuantityNumber - 0) < Double.Epsilon)
                {
                    ShowNotificationDialog("Si assicuri di aver inserito un numero maggiore di zero come quantità.");
                    _addIngredientControl.tb_quantity.Focus();
                    return;
                }

                var currentMeasure = _addIngredientControl.cb_measures.SelectedItem as string;
                if (currentMeasure == null)
                {
                    ShowNotificationDialog("Si assicuri di aver selezionato una unità di misura.");
                    _addIngredientControl.cb_measures.Focus();
                    return;
                }

                var currentNotes = _addIngredientControl.tb_notes.Text;

                if (_addIngredientControl.CurrentIngredient == null)
                {
                    var i = new IngredientFromRecipe(selectedIngredient, currentNotes,
                                                     currentQuantityNumber, currentMeasure);
                    _panel.ingredients.Add(i);
                }
                else
                {
                    _addIngredientControl.CurrentIngredient.Measure = currentMeasure;
                    _addIngredientControl.CurrentIngredient.Quantity = currentQuantityNumber;
                    _addIngredientControl.CurrentIngredient.Notes = currentNotes;
                    // workaround to fire up a data changed event
                    var index = _panel.ingredients.IndexOf(_addIngredientControl.CurrentIngredient);
                    _panel.ingredients.RemoveAt(index);
                    _panel.ingredients.Insert(index, _addIngredientControl.CurrentIngredient);
                }
            }
            _panel.bt_salva.IsEnabled = _panel.IsModified();
            rightContentPane.Content = _panel;
        }

        void Bt_Chiudi_Ingredient_Control_Click(object sender, RoutedEventArgs routedEventArgs)
        {
            if (_addIngredientControl.IsModified())
            {
                //"Vuoi salvare le modifiche?"
                var result = MessageBox.Show((string)Application.Current.FindResource("want_to_save"),
                                             (string)Application.Current.FindResource("notification_dialog_type"), MessageBoxButton.YesNoCancel,
                                             MessageBoxImage.Warning);

                switch (result)
                {
                    case MessageBoxResult.Yes:
                        _addIngredientControl.bt_salva.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));
                        break;
                    case MessageBoxResult.No:
                        break;
                    case MessageBoxResult.Cancel:
                        return;
                }
            }
            rightContentPane.Content = _panel;
        }

        #endregion

        #region event_handlers_for_StepSubControl

        void Bt_Salva_Step_Control_Click(object sender, RoutedEventArgs routedEventArgs)
        {
            if (_addStepControl.IsModified())
            {
                if (_addStepControl.rb_generic_step.IsChecked.HasValue && _addStepControl.rb_generic_step.IsChecked.Value)
                {
                    if (_addStepControl._genericStepControl.tb_step_description.Text.Equals(""))
                    {
                        ShowNotificationDialog("Si assicuri di aver inserito una descrizione del passo.");
                        _addStepControl._genericStepControl.tb_step_description.Focus();
                        return;
                    }

                    //if (_addStepControl._genericStepControl.tb_employed_resorces.Text.Equals(""))
                    //{
                    //    ShowNotificationDialog("Si assicuri di aver inserito delle risorse occupate del passo.");
                    //    _addStepControl._genericStepControl.tb_employed_resorces.Focus();
                    //    return;
                    //}

                }
                else
                {
                    if (_addStepControl._subRecipeStepControl.cb_recipes.SelectedIndex == -1)
                    {
                        ShowNotificationDialog("Si assicuri di aver selezionato una sottoricetta relativa al passo.");
                        _addStepControl._subRecipeStepControl.cb_recipes.Focus();
                        return;
                    }

                    //if (_addStepControl._subRecipeStepControl.cb_servings.SelectedIndex == -1)
                    //{
                    //    ShowNotificationDialog("Si assicuri di aver selezionato le porzioni per la sottoricetta.");
                    //    _addStepControl._subRecipeStepControl.cb_servings.Focus();
                    //    return;
                    //}
                }

                Mouse.OverrideCursor = Cursors.Wait;
                if (_addStepControl.CurrentStep == null)
                {
                    StepFromRecipe s;
                    int id;

                    if (_addStepControl.AddBefore)
                    {
                        if (_addStepControl.SelectedId == -1 || _addStepControl.SelectedId == 0)
                            id = 1;
                        else
                            id = _addStepControl.SelectedId + 1;
                    } else
                    {
                        if (_addStepControl.SelectedId == -1 || _addStepControl.SelectedId == _panel.steps.Count - 1)
                            id = _panel.steps.Count + 1;
                        else
                            id = _addStepControl.SelectedId + 2;
                    }


                    if (_addStepControl.rb_generic_step.IsChecked.HasValue && _addStepControl.rb_generic_step.IsChecked.Value)
                        s = new StepFromRecipe(id,
                                               _addStepControl._genericStepControl.tb_step_description.Text,
                                               _addStepControl._genericStepControl.tb_employed_resorces.Text,
                                               _addStepControl.cb_tempoOre.SelectedItem as int?,
                                               _addStepControl.cb_tempoMin.SelectedItem as int?);
                    else
                        s = new StepFromRecipe(id,
                                               _addStepControl._subRecipeStepControl.cb_recipes.SelectedItem as string,
                                               _addStepControl._subRecipeStepControl.cb_servings.SelectedItem as int?,
                                               _addStepControl.cb_tempoOre.SelectedItem as int?,
                                               _addStepControl.cb_tempoMin.SelectedItem as int?);

                    if (s.UpdatedId - 1 == _panel.steps.Count )
                        _panel.steps.Add(s);
                    else
                    {
                        _panel.steps.Insert(s.UpdatedId - 1, s);

                        for (var i = s.UpdatedId; i < _panel.steps.Count; i++)
                        {
                            var curS = _panel.steps[i];
                            _panel.steps.RemoveAt(i);
                            curS.UpdatedId++;
                            _panel.steps.Insert(i, curS);
                        }
                        
                    }

                    _panel.lv_steps.SelectedItem = s;
                }
                else
                {
                    var cs = _addStepControl.CurrentStep;
                    if (_addStepControl.rb_generic_step.IsChecked.HasValue && _addStepControl.rb_generic_step.IsChecked.Value)
                    {
                        
                        cs.Type = StepType.Generic;
                        cs.Description = _addStepControl._genericStepControl.tb_step_description.Text;
                        cs.Resources = _addStepControl._genericStepControl.tb_employed_resorces.Text;
                    }
                    else
                    {
                        cs.Type = StepType.SubRecipe;
                        cs.SubRecipeName = _addStepControl._subRecipeStepControl.cb_recipes.SelectedItem as string;
                        cs.Servings = _addStepControl._subRecipeStepControl.cb_servings.SelectedItem as int?;
                        cs.UpdateDescription();
                    }
                    cs.StepHours = _addStepControl.cb_tempoOre.SelectedItem as int?;
                    cs.StepMinutes = _addStepControl.cb_tempoMin.SelectedItem as int?;

                    var i = _panel.steps.IndexOf(cs);
                    _panel.steps.RemoveAt(i);
                    _panel.steps.Insert(i, cs);
                }
            }

            _panel.bt_salva.IsEnabled = _panel.IsModified();
            rightContentPane.Content = _panel;

            Mouse.OverrideCursor = null;
        }


        void Bt_Chiudi_Step_Control_Click(object sender, RoutedEventArgs routedEventArgs)
        {
            if (_addStepControl.IsModified())
            {
                //"Vuoi salvare le modifiche?"
                var result = MessageBox.Show((string)Application.Current.FindResource("want_to_save"),
                                             (string)Application.Current.FindResource("notification_dialog_type"), MessageBoxButton.YesNoCancel,
                                             MessageBoxImage.Warning);

                switch (result)
                {
                    case MessageBoxResult.Yes:
                        _addStepControl.bt_salva.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));
                        break;
                    case MessageBoxResult.No:
                        break;
                    case MessageBoxResult.Cancel:
                        return;
                }
            }
            rightContentPane.Content = _panel;
        }

        #endregion

        #region event_handlers_forNoteSubControl

        void Bt_Chiudi_Note_Control_Click(object sender, RoutedEventArgs e)
        {
            if (_addNoteControl.IsModified())
            {
                //"Vuoi salvare le modifiche?"
                var result = MessageBox.Show((string)Application.Current.FindResource("want_to_save"),
                                                (string)Application.Current.FindResource("notification_dialog_type"), MessageBoxButton.YesNoCancel,
                                                MessageBoxImage.Warning);

                switch (result)
                {
                    case MessageBoxResult.Yes:
                        _addStepControl.bt_salva.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));
                        break;
                    case MessageBoxResult.No:
                        break;
                    case MessageBoxResult.Cancel:
                        return;
                }
            }

            rightContentPane.Content = _panel;
        }

        void Bt_Salva_Note_Control_Click(object sender, RoutedEventArgs e)
        {
            Mouse.OverrideCursor = Cursors.Wait;
            if (_addNoteControl.IsModified())
                _panel.lv_trials.Items.Add(_addNoteControl.tb_note_description.Text);

            _panel.bt_salva.IsEnabled = _panel.IsModified();
            rightContentPane.Content = _panel;
            Mouse.OverrideCursor = null;
        }

        #endregion

        #region ButtonHandlers

        public void Bt_Back_Click(object sender, RoutedEventArgs e)
        {
            if (!Save_Context()) return;
            Manager.ClearCache();
            Switcher.Switch(new MainMenu());
        }

        public void Lb_Items_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            bt_delete.IsEnabled = lb_items.SelectedItem != null;

            if (_refreshing) return;

            if (Save_Context())
            {
                Refresh_Recipe_List();
                _panel.CurrentRecipe = (string) lb_items.SelectedValue;
            }

            if (rightContentPane.Content == null)
                rightContentPane.Content = _panel;

        }

        public void Bt_Add_Click(object sender, RoutedEventArgs e)
        {
            if (!Save_Context())
                return;

            _refreshing = true;
            lb_items.SelectedItem = null;
            _refreshing = false;

            _panel.CurrentRecipe = "";

            if (rightContentPane.Content == null)
                rightContentPane.Content = _panel;
        }

		public void Bt_Import_Click(object sender, RoutedEventArgs e) {
			if (!Save_Context())
				return;

			_refreshing = true;
			lb_items.SelectedItem = null;
			_refreshing = false;

			rightContentPane.Content = null;

			var dialog = new OpenFileDialog {
				Title = "Scegli il file della ricetta da importare"
			};

			if (dialog.ShowDialog() == DialogResult.OK) {

				try
				{
					var importPreview = new ImportPreview()
					{
						CurrentRecipe = RecipeImporter.importRecipe(dialog.FileName)

					};
					if (Manager.Recipes.Contains(importPreview.CurrentRecipe.Name))
					{
						MessageBox.Show("Errore nell'importazione del file - Esiste già una ricetta con questo nome", "Avviso",
							MessageBoxButton.OK,
							MessageBoxImage.Error);
					}
					else
					{
						importPreview.ShowDialog();
						Refresh_Recipe_List();
					}
					
				}
				catch (DuplicateKeywordException)
				{
					MessageBox.Show("Errore nell'importazione del file - Una parola chiave è ripetuta più volte", "Avviso",
								MessageBoxButton.OK,
								MessageBoxImage.Error);	
				}
				catch (DuplicateIngredientException)
				{
					MessageBox.Show("Errore nell'importazione del file - Lo stesso ingrediente è ripetuto più volte", "Avviso",
								MessageBoxButton.OK,
								MessageBoxImage.Error);	
				}
				catch (MissingRecipeNameException)
				{
					MessageBox.Show("Errore nell'importazione del file - Non è presente il nome della ricetta", "Avviso",
								MessageBoxButton.OK,
								MessageBoxImage.Error);	
				}
				catch (ParsingException)
				{
					MessageBox.Show("Errore nell'importazione del file", "Avviso",
								MessageBoxButton.OK,
								MessageBoxImage.Error);	
				}
				
			}
		}

        public void Bt_Delete_Click(object sender, RoutedEventArgs e)
        {
            var currentRecipe = lb_items.SelectedItem as string;

            if (currentRecipe == null)
                return;


            IEnumerable<string> canDeleteMessage;
            var canDelete = Data.Operations.Operations.CanRemoveRecipe(currentRecipe, out canDeleteMessage);
            var msgFromCanRemove = canDeleteMessage.Aggregate("", (current, m) => current + (Environment.NewLine + m));

            var msgStr = "";

            if (canDelete)
            {
                msgStr += (string)Application.Current.FindResource("ElementCanBeDeleted");
                if (!msgFromCanRemove.Equals(""))
                    msgStr += " " + (string)Application.Current.FindResource("ElementIsUsedBy") + msgFromCanRemove;

                var result = MessageBox.Show(msgStr, (string)Application.Current.FindResource("notification_dialog_type"), MessageBoxButton.YesNo,
                                                MessageBoxImage.Warning);

                switch (result)
                {
                    case MessageBoxResult.Yes:
                        Mouse.OverrideCursor = Cursors.Wait;

                        Manager.Recipes.Remove(currentRecipe);

                        _panel.Editing = false;

                        _refreshing = true;
                        lb_items.SelectedItem = null;
                        lb_items.Items.Remove(currentRecipe);
                        _refreshing = false;

                        rightContentPane.Content = null;
                        Mouse.OverrideCursor = null;
                        break;
                    case MessageBoxResult.No:
                        break;
                }
            }
            else
            {
                msgStr = (string)Application.Current.FindResource("ElementCannotBeDeleted") + msgFromCanRemove;
                MessageBox.Show(msgStr, (string)Application.Current.FindResource("notification_dialog_type"), MessageBoxButton.OK,
                                                MessageBoxImage.Warning);
            }

        }

        public void Bt_Search_Click(object sender, RoutedEventArgs e)
        {
            Refresh_Recipe_List();
        }


        public void Bt_Clear_Search_Click(object sender, RoutedEventArgs e)
        {
            tb_search.Text = "";
            Refresh_Recipe_List();
        }

        #endregion

        #region ISwitchable Members

        public void UtilizeState(object state)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region SaveCommandRegion

        readonly CommandBinding _savebinding = new CommandBinding(ApplicationCommands.Save, CommandSaveHandler);

        static void CommandSaveHandler(object target, ExecutedRoutedEventArgs e)
        {
            var t = target as RecipeUserControl;
            if (t == null)
                return;

            Mouse.OverrideCursor = Cursors.Wait;

            if (t._panel.SaveCurrentRecipe())
                t.Refresh_Recipe_List();

            if (t.rightContentPane.Content != null)
                t.lb_items.SelectedItem = t._panel.tb_nomeRicetta.Text;

            Mouse.OverrideCursor = null;
        }

        #endregion

        #region CloseCommandRegion

        readonly CommandBinding _closebinding = new CommandBinding(ApplicationCommands.Close, CommandCloseHandler);

        static void CommandCloseHandler(object target, ExecutedRoutedEventArgs e)
        {
            var t = target as RecipeUserControl;
            if (t == null)
                return;

            Mouse.OverrideCursor = Cursors.Wait;
            if (t.Save_Context())
            {
                t._panel.Editing = false;

                t._refreshing = true;
                t.lb_items.SelectedItem = null;
                t._refreshing = false;

                t.rightContentPane.Content = null;
                t.Refresh_Recipe_List();
            }
            Mouse.OverrideCursor = null;
        }

        #endregion

        static void ShowNotificationDialog(string message)
        {
            MessageBox.Show(message,
                            (string)Application.Current.FindResource("notification_dialog_type"),
                            MessageBoxButton.OK,
                            MessageBoxImage.Error);
        }

		void Tb_search_OnKeyDown(object sender, KeyEventArgs e) {
			if (e.Key == Key.Enter) {
				e.Handled = true;
				bt_search.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));

			}
		}

	    

    }
}